/***************************************************************************
 *   Copyright (C) 2008 by Ivan Blagoev Topolsky   *
 *   ivan.topolsky@genebio.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 3 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef XENO_H
#define XENO_H

#include <vector>

// Captain-bol
#include <spectrumpeakrefdualptr.h>
#include <spectrumlcmscollection.h>
#include <spectrumlcmsms.h>


namespace xeno {
	using namespace std;	// STL
	typedef vector<long long> ExtractList;
	
	
// TODO this kind of logic should be moved to Captain-bol as it is not-reader specific

static inline SpectrumPeakRefDualPtr<PeakIntensity>* FindParentPeak(SpectrumLcms* parsp, SpectrumLcmsms* sp, const double MoZ, double* it=NULL) {
	if (parsp == NULL) 
		return NULL;

	// FIXME this will be slow on big runs. Using a massindex could be handy
	// FIXME a binary search is another possibility
	
	if (! parsp->empty()) {
		// scan all masses to find the smallest
		SpectrumLcms::iterator mass = parsp->begin();
		while (mass != parsp->end()) 
			// FIXME use a DeltaMass for comparing
			// TODO in fact, a std::min on the translation vector Spectrum[i] -> DeltaMass(Spectrum[i]) would be the most elegant solution, but we loose the index or binary search speed up
			if (fabs(MoZ - (*mass)->moz()) < .1) {
				// Match !
				if (it) //  store the intensity
					*it = (*mass)->intensity();
				// and build the reference
				return  new SpectrumPeakRefDualPtr<PeakIntensity> (parsp, (*mass));
			} else
				++mass;
	}
	
	// can't find a parent peak
	return  new SpectrumPeakRefDualPtr<PeakIntensity> (parsp, NULL);
}

static inline SpectrumPeakRefDualPtr<PeakIntensity>* FindParentSpectrum(SpectrumLcmsCollection& col, SpectrumLcmsms* sp, const double MoZ, double* it=NULL) {
	if (col.empty()) {
		// no precursors ? -> no parents !
		return NULL;
	}

	if (it)
		 *it = 0.;
	// scan time axis
	// FIXME this will be slow on big runs. A timeindex (similar to the mass index for MS^2) could be handy
	// FIXME a binary search is another possibility

	// NOTE this works because analyst stores the spectra ordered by time inside a given experiment
	// and thus, the spectra where added to RunLcmsms chronologically.
	// FIXME URGENT add a sort to support other non-chronologically ordered readers (Xcalibur)
	// NOTE currently, most Xcalibur dataset happen to have the MS1 spectra in grossly chronological order, so it mostly works anyway

	// first find the last MS^1 before current t
	SpectrumLcmsCollection::iterator time = col.begin();
	// post-fix : the *previous* loop was the last. (i.e.: do one more loop *with* the tail)
	while ((time++) != col.end()) 
		if ((time == col.end()) // past the last ? the last is the one we need.
		    || (*time)->retentionTime() > sp->retentionTime()) { // found 1 which is older than t
			if (time == col.begin())
				return NULL; // even the first MS^1 is older than t ? Bail out !
			else
				--time; // move back to the last whose retention time was befor curent t.

			// Ok, we find the preceding MS^1 spectum
			// now scan all masses
			return FindParentPeak((*time), sp, MoZ, it);
		}

	return NULL;
}



}
#endif
